﻿using AiQiuQuan.Sport.Core;
using AiQiuQuan.Sport.Core.WechatApi;
using AiQiuQuan.Sport.Model.Models;
using EasyCaching.Core;
using Microsoft.Extensions.Options;
using SKIT.FlurlHttpClient.Wechat.Api;
using SKIT.FlurlHttpClient.Wechat.Api.Models;
using System.Web;

namespace AiQiuQuan.Sport.WebApi.Services.Impl
{
    /// <summary>
    /// AccessTokenService
    /// </summary>
    public class AccessTokenService : IAccessTokenService
    {
        private readonly WechatApiOption _wechatApiOption;
        private readonly IRedisCachingProvider _redis;
        private readonly ILogger<AccessTokenService> _logger;
        private readonly IWechatApiHttpClientFactory _wechatApiHttpClientFactory;

        /// <summary>
        /// ctor
        /// </summary>
        public AccessTokenService(
            IOptions<WechatApiOption> wecahtApiOptions,
            IRedisCachingProvider redis,
            ILogger<AccessTokenService> logger,
            IWechatApiHttpClientFactory wechatApiHttpClientFactory)
        {
            _redis = redis;
            _logger = logger;
            _wechatApiOption = wecahtApiOptions.Value;
            _wechatApiHttpClientFactory = wechatApiHttpClientFactory;
        }

        /// <summary>
        /// 微信公众号AccessToken
        /// </summary>
        public async Task<UnaryResult<TokenDto>> GetWxMpAccessTokenAsync()
        {
            var result = new TokenDto();
            var key = $"{_wechatApiOption.MPAppId}_at";
            var value = await _redis.StringGetAsync(key);
            if (string.IsNullOrWhiteSpace(value))
            {
                var apiClient = _wechatApiHttpClientFactory.Create(_wechatApiOption.MPAppId, _wechatApiOption.MPAppSecret);
                var request = new CgibinTokenRequest();
                var rep = await apiClient.ExecuteCgibinTokenAsync(request);
                if (!rep.IsSuccessful())
                {
                    var error = $"微信公众号accessToken错误:{rep.ErrorCode},{rep.ErrorMessage}";
                    _logger.LogError(error);
                    return UnaryResult.From(10, result, error);
                }

                result.AccessToken = rep.AccessToken;
                result.Expire = rep.ExpiresIn;
                await _redis.StringSetAsync(key, $"{result.AccessToken}^{result.Expire}", TimeSpan.FromSeconds(result.Expire - 300));
            }
            else
            {
                var valueArray = value.Split('^');
                result.AccessToken = valueArray[0];
                result.Expire = int.Parse(valueArray[1]);
            }

            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 微信小程序AccessToken
        /// </summary>
        public async Task<UnaryResult<TokenDto>> GetWxMiniProgramAccessTokenAsync()
        {
            var result = new TokenDto();
            var key = $"{_wechatApiOption.MiniProgramAppId}_at";
            var value = await _redis.StringGetAsync(key);
            if (string.IsNullOrWhiteSpace(value))
            {
                var apiClient = _wechatApiHttpClientFactory.Create(_wechatApiOption.MiniProgramAppId, _wechatApiOption.MiniProgramAppSecret);
                var request = new CgibinTokenRequest();
                var rep = await apiClient.ExecuteCgibinTokenAsync(request);
                if (!rep.IsSuccessful())
                {
                    var error = $"微信小程序accessToken错误:{rep.ErrorCode},{rep.ErrorMessage}";
                    _logger.LogError(error);
                    return UnaryResult.From(10, result, error);
                }

                result.AccessToken = rep.AccessToken;
                result.Expire = rep.ExpiresIn;
                await _redis.StringSetAsync(key, $"{result.AccessToken}^{result.Expire}", TimeSpan.FromSeconds(result.Expire - 300));
            }
            else
            {
                var valueArray = value.Split('^');
                result.AccessToken = valueArray[0];
                result.Expire = int.Parse(valueArray[1]);
            }

            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 获取微信网页授权URL
        /// </summary>
        /// <param name="callbakcUrl">微信授权成功回调地址(全路径地址)</param>
        /// <param name="scope">snsapi_base(默认)、snsapi_userinfo</param>
        /// <param name="state">授权成功重定向参数，可以填写a-zA-Z0-9的参数值，最多128字节</param>
        public async Task<string> GetWxWebAuthorizeUrlAsync(string callbakcUrl, string scope = "snsapi_base", string state = "")
        {
            var url = $"https://open.weixin.qq.com/connect/oauth2/authorize?appid={_wechatApiOption.MPAppId}&redirect_uri={HttpUtility.UrlEncode(callbakcUrl)}&response_type=code&scope={scope}&state={state}&forcePopup=true#wechat_redirect";
            return await Task.FromResult(url);
        }

        /// <summary>
        /// 获取微信网页token
        /// </summary>
        /// <param name="code">授权成功获得的code</param>
        public async Task<UnaryResult<WxWebTokenDto>> GetWxMpWebAccessTokenAsync(string code)
        {
            var result = new WxWebTokenDto();
            var apiClient = _wechatApiHttpClientFactory.Create(_wechatApiOption.MPAppId, _wechatApiOption.MPAppSecret);
            var request = new SnsOAuth2AccessTokenRequest { Code = code };
            var rep = await apiClient.ExecuteSnsOAuth2AccessTokenAsync(request);
            if (!rep.IsSuccessful())
            {
                var error = $"微信网页accessToken错误:{rep.ErrorCode},{rep.ErrorMessage}";
                _logger.LogError(error);
                return UnaryResult.From(10, result, error);
            }

            result.AccessToken = rep.AccessToken;
            result.Expire = rep.ExpiresIn;
            result.MpOpenId = rep.OpenId;
            result.RefreshToken = rep.RefreshToken;
            result.Scope = rep.Scope;

            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 微信公众号JSSDK TICKET
        /// </summary>
        public async Task<UnaryResult<JsSdkTicket>> GetWxMpJsSdkTicketAsync()
        {
            var result = new JsSdkTicket();
            var key = $"{_wechatApiOption.MPAppId}_jst";
            var value = await _redis.StringGetAsync(key);
            if (string.IsNullOrWhiteSpace(value))
            {
                var accessTokenResult = await GetWxMpAccessTokenAsync();
                if (accessTokenResult.Code != 0)
                {
                    var error = $"微信公众号jssdk ticket错误:{accessTokenResult.Msg}";
                    _logger.LogError(error);
                    return UnaryResult.From(10, result, error);
                }

                var request = new CgibinTicketGetTicketRequest { AccessToken = accessTokenResult.Data.AccessToken };
                var apiClient = _wechatApiHttpClientFactory.Create(_wechatApiOption.MPAppId, _wechatApiOption.MPAppSecret);
                var rep = await apiClient.ExecuteCgibinTicketGetTicketAsync(request);
                if (!rep.IsSuccessful())
                {
                    var error = $"微信公众号jssdk ticket错误:{rep.ErrorCode},{rep.ErrorMessage}";
                    _logger.LogError(error);
                    return UnaryResult.From(10, result, error);
                }

                result.Ticket = rep.Ticket;
                result.Expire = rep.ExpiresIn;
                await _redis.StringSetAsync(key, $"{result.Ticket}^{result.Expire}", TimeSpan.FromSeconds(result.Expire - 300));
            }
            else
            {
                var valueArray = value.Split('^');
                result.Ticket = valueArray[0];
                result.Expire = int.Parse(valueArray[1]);
            }

            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 微信 jssdk config
        /// </summary>
        /// <param name="url">调用jssdk的完整url</param>
        public async Task<UnaryResult<IDictionary<string, string>>> GetWxJsSdkConfigAsync(string url)
        {
            var jsticketResult = await GetWxMpJsSdkTicketAsync();
            if (jsticketResult.Code != 0)
            {
                return UnaryResult.From<IDictionary<string, string>>(10, null, jsticketResult.Msg);
            }

            var apiClient = _wechatApiHttpClientFactory.Create(_wechatApiOption.MPAppId, _wechatApiOption.MPAppSecret);
            var result = apiClient.GenerateParametersForJSSDKConfig(jsticketResult.Data.Ticket, url);
            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 微信小程序登录结果
        /// </summary>
        /// <param name="jsCode">小程序端登录获取的code</param>
        public async Task<UnaryResult<WxMiniProgramLoginDto>> GetWxMminiProgramLoginResultAsync(string jsCode)
        {
            var result = new WxMiniProgramLoginDto();
            var apiClient = _wechatApiHttpClientFactory.Create(_wechatApiOption.MiniProgramAppId, _wechatApiOption.MiniProgramAppSecret);
            var request = new SnsComponentJsCode2SessionRequest { JsCode = jsCode };
            var rep = await apiClient.ExecuteSnsJsCode2SessionAsync(request);
            if (!rep.IsSuccessful())
            {
                var error = $"微信小程序登录错误:{rep.ErrorCode},{rep.ErrorMessage}";
                _logger.LogError(error);
                return UnaryResult.From(10, result, error);
            }

            result.OpenId = rep.OpenId;
            result.UnionId = rep.UnionId;
            result.SessionKey = rep.SessionKey;

            return UnaryResult.Succeed(result);
        }
    }
}